package game

import (
	"time"

	. "gddgame.cc/galaxy/common/dsl/game"
	"gddgame.cc/galaxy/common/dsl/game/reward"
	. "gddgame.cc/galaxy/common/dsl/game/task"
	"gddgame.cc/galaxy/common/service/playbook"
	"gddgame.cc/galaxy/common/service/playbook/game_user"
	"gddgame.cc/galaxy/project/maze/maze/model"
)

type FindScene struct {
	center *Center
	*game_user.PlayerManager

	manager playbook.SceneManager

	// 结束判断
	endFactor []Factor

	number       int32
	total        int32
	DurationTime time.Duration

	finish chan<- struct{}
}

func NewFindScene(center *Center, manager *game_user.PlayerManager) *FindScene {
	s := &FindScene{
		center:        center,
		PlayerManager: manager,

		number:       int32(model.FindGameNumber),
		DurationTime: 30 * 5 * time.Second,
	}
	return s
}

func (scene *FindScene) ID() string {
	return "find"
}

func (scene *FindScene) Data() *playbook.Data {
	return &playbook.Data{
		StatData:      scene.center.StatData,
		ObjectData:    nil,
		TargetData:    nil,
		RealtimeIndex: []int{0},
		DataStatKey: map[int]string{
			0: FindStatKey,
		},
	}
}

func (scene *FindScene) Bind(manager playbook.SceneManager) {
	scene.manager = manager
}

func (scene *FindScene) Ticker() time.Duration {
	return time.Second
}

func (scene *FindScene) GenerateTargetList() []int {
	return []int{}
}

func (scene *FindScene) GenerateObjectList() []int {
	return []int{}
}

func (scene *FindScene) Tasks() map[int]*GameTask {
	return map[int]*GameTask{}
}

func (scene *FindScene) InitScene(players []*playbook.Player) playbook.InfoArray {
	infos := []playbook.InfoDetail{}
	// 添加用户目标
	for index, player := range players {
		infos = append(infos, playbook.InfoDetail{Key: playbook.TargetKey, Value: scene.center.GeneratePlayer(player, scene.UserMap[player.OpenId].(*model.User), index)})
		scene.PlayerMap[player.OpenId] = index
	}
	// 下发地图信息: 可根据zone大小,环境设定
	infos = append(infos, playbook.InfoDetail{Key: playbook.MapKey, Value: &playbook.MapInfo{X: 25, Y: 25, Type: 1}})

	// 下发UI信息
	infos = append(infos, playbook.InfoDetail{Key: playbook.UiKey, Value: &playbook.UiInfo{Event: InfoUiEvent, Key: TimeUiKey, Value: int(scene.manager.StartTime().Add(scene.DurationTime).Unix())}})
	infos = append(infos, playbook.InfoDetail{Key: playbook.UiKey, Value: &playbook.UiInfo{Event: InfoUiEvent, Key: NumberUiKey, Value: int(scene.number)}})
	infos = append(infos, playbook.InfoDetail{Key: playbook.UiKey, Value: &playbook.UiInfo{Event: InfoUiEvent, Key: ModeUiKey, Value: int(model.FindGame)}})
	scene.endFactor = []Factor{{
		Source: PlaybookSource,
		Key:    FindStatKey,
		Value:  int32(scene.number),
	}}
	return infos
}

func (scene *FindScene) InitPlayer(player *playbook.Player) playbook.InfoArray {
	infos := []playbook.InfoDetail{}
	if scene.PlayerMap[player.OpenId] == 0 {
		infos = append(infos, playbook.InfoDetail{Key: playbook.MasterKey, Value: 1})
	}
	// 创建用户
	infos = append(infos, playbook.InfoDetail{Key: playbook.IdentityKey, Value: 1})
	infos = append(infos, playbook.InfoDetail{Key: playbook.MakeKey, Value: &playbook.MakeInfo{Id: scene.PlayerMap[player.OpenId], Category: playbook.TargetMake, Relation: playbook.PlayerMake, X: 0, Y: 0, Z: 0}})
	if scene.HasAi {
		for _, index := range scene.PlayerMap {
			if index == 0 {
				continue
			}
			infos = append(infos, playbook.InfoDetail{Key: playbook.MakeKey, Value: &playbook.MakeInfo{Id: index, Category: playbook.TargetMake, Relation: playbook.AiPlayerMake, X: 0, Y: 0, Z: 0}})
		}
	}
	return infos
}

func (scene *FindScene) Start(finish chan<- struct{}) {
	scene.finish = finish
}

func (scene *FindScene) UpdatePlayer(player *playbook.Player) playbook.InfoArray {
	infos := []playbook.InfoDetail{}
	return infos
}

func (scene *FindScene) UpdateTicker(languages []string) playbook.InfoArray {
	infos := []playbook.InfoDetail{}

	t := time.Now().Sub(*scene.manager.StartTime())
	if t >= scene.DurationTime {
		// 结束
		scene.finish <- struct{}{}
	}
	return infos
}

func (scene *FindScene) UpdateData() playbook.InfoArray {
	infos := []playbook.InfoDetail{}

	total := scene.manager.GetStat(PlaybookSource, FindStatKey)
	if total > scene.number && total <= scene.number {
		scene.total = total
		n := scene.number - total
		if n < 0 {
			n = 0
		}
		infos = append(infos, playbook.InfoDetail{Key: playbook.UiKey, Value: &playbook.UiInfo{Event: InfoUiEvent, Key: NumberUiKey, Value: int(n)}})
		//fmt.Println("scene", scene.total)
	}
	// 失败判断
	if scene.endFactor != nil && scene.manager.Judge(scene.endFactor) {
		scene.finish <- struct{}{}
	}
	return infos
}

func (scene *FindScene) Refresh(players []*playbook.Player) {

}

func (scene *FindScene) Finish(pb *playbook.Playbook) {
	//// 统计最大战斗记录拥有者
	//_ = pb.MaxStat()

	prs := make([]*model.PlayerResult, len(pb.Players))
	idMap := make(map[string]int, len(pb.Players))

	for index, player := range pb.Players {
		user := scene.UserMap[player.OpenId].(*model.User)
		pr := &model.PlayerResult{
			Entity: user.Entity,
			Score:  user.OnlineScore,
			Name:   player.Open.NickName,
			Find:   int(scene.manager.GetPlayerStat(player, PlaybookUserSource, FindStatKey)),
		}
		prs[index] = pr
	}

	for index, player := range pb.Players {
		// 初始化战斗记录
		result := &model.GameResult{}

		// 评分
		scene.Score(pb, player, result)
		// 合并剧本统计信息到用户
		scene.mergeStat(pb, player, result)

		idMap[player.OpenId] = index

		// 合并所有用户信息到Result
		result.Self = prs[index]
		result.Other = prs[1-index]

		player.Result = result
	}
}

func (scene *FindScene) Score(pb *playbook.Playbook, player *playbook.Player, result *model.GameResult) {
	total := scene.manager.GetStat(PlaybookSource, FindStatKey)
	self := scene.manager.GetPlayerStat(player, PlaybookUserSource, FindStatKey)
	//fmt.Println(total, self)
	if self*2 > total {
		result.Reward = model.OnlineReward
		result.Score = 1
		result.Success = true
	} else if self*2 < total {
		result.Reward = &reward.GoldReward{}
		result.Success = false
		result.Score = -1
	} else {
		result.Reward = &reward.GoldReward{}
		result.Success = false
		result.Score = 0
	}
}

func (scene *FindScene) mergeStat(pb *playbook.Playbook, player *playbook.Player, result *model.GameResult) map[string]int {
	// 统计任务数
	// 统计战斗记录，以及场景记录
	player.Playbook[model.PlaybookTimes] = 1
	// 关联战斗时长
	player.Playbook[model.PlaybookTime] = int32(time.Now().Unix()-pb.StartTime().Unix()) / 60
	player.Playbook[scene.ID()] = 1
	// 将用户的playbook数据合并到用户统计数据中去
	stats := make(map[string]int)
	for k, v := range player.Playbook {
		stat, ok := pb.Stats[k]
		if !ok {
			continue
		}

		if stat.IsGameResult {
			// 只保存需要统计的统计项
			stats[stat.Key] = int(v)
		}
	}
	return stats
}
